import {
    ArgumentsHost,
    Catch,
    ExceptionFilter,
    HttpException,
    HttpStatus,
} from '@nestjs/common';
import { ErrorCode } from '../../constants/error';
import { MyLoggerService } from '../../common/logger.service';

@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
  constructor(
    private readonly logger: MyLoggerService,
  ) {}

  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const nestjsMessage = exception.message;
    let message;
    let errorCode: number;

    if (exception.code === 'EBADCSRFTOKEN') {
      response.status(HttpStatus.FORBIDDEN).json({
        code: ErrorCode.Forbidden.CODE,
        message: 'invalid csrf token',
      });
      return;
    } else if (exception.getStatus) { // http exception
      const httpException: HttpException = exception as HttpException;
      const exceptionResponse = httpException.getResponse()
      if (httpException.message && typeof exceptionResponse['errorCode'] !== 'undefined') {
          errorCode = exceptionResponse['errorCode'];
          message = exceptionResponse['message'] || ErrorCode.CodeToMessage(errorCode);
      } else {
        const statusCode = httpException.getStatus();
        if (ErrorCode.HasCode(statusCode)) {
          message = ErrorCode.CodeToMessage(statusCode);
        } else {
          errorCode = ErrorCode.ERROR.CODE;
          message = ErrorCode.ERROR.MESSAGE;
        }
      }
    } else {
      // 报错抛出的Error
      errorCode = ErrorCode.ERROR.CODE;
      message = ErrorCode.ERROR.MESSAGE;
      this.logger.error({
        message: [ exception.message, exception.stack ].join('\n'),
      });
    }

    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    response.status(status).json({
      code: errorCode,
      message,
      data: process.env.NODE_ENV === 'dev' ? {
        nestjs: nestjsMessage,
      } : null,
    });
  }
}